home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 19 / CU Amiga Magazine's Super CD-ROM 19 (1998)(EMAP Images)(GB)[!][issue 1998-02].iso / CUCD / Programming / LEDA / source / src / basic / _rational.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-16  |  7.4 KB  |  356 lines

  1. /*******************************************************************************
  2. +
  3. +  LEDA  3.1c
  4. +
  5. +
  6. +  _rational.c
  7. +
  8. +
  9. +  Copyright (c) 1994  by  Max-Planck-Institut fuer Informatik
  10. +  Im Stadtwald, 6600 Saarbruecken, FRG     
  11. +  All rights reserved.
  12. *******************************************************************************/
  13.  
  14.  
  15. #include <LEDA/basic.h>
  16. #include <LEDA/rational.h>
  17. #include <math.h>
  18. #include <ctype.h>
  19.  
  20.  
  21.  
  22. // hidden functions
  23.  
  24. LedaRational& LedaRational::normalize()
  25. // divide numerator and denominator by their greatest common divisor
  26.   { // den is assumed to be nonzero and positive
  27.     if (num == den) { num = den = 1; return (*this); }
  28.     if (-num == den) { num = -1; den = 1; return (*this); }
  29.     Int ggt = bgcd(num, den);
  30.     if (!Ieq1(ggt)) {
  31.       num /= ggt;
  32.       den /= ggt;
  33.     };
  34.     return (*this);
  35.   };
  36.  
  37.  
  38.  
  39. // Constructors
  40.  
  41. LedaRational::LedaRational(double x)
  42. // from the GNU-C++ library (MACHINE-DEPENDENT)
  43.   { num = 0; den = 1;
  44.  
  45.     if (x != 0.0)
  46.     { int neg = (x < 0);
  47.       if (neg) x = -x;
  48.  
  49.       const unsigned shift = 15;     // a safe shift per step
  50.       const double width = 32768;    // = 2^shift
  51.       const int maxiter = 20;        // ought not be necessary, but just in case,
  52.                                      // max 300 bits of precision
  53.       int expt;
  54.       double mantissa = frexp(x, &expt);
  55.       long exponent = expt;
  56.       double intpart;
  57.       int k = 0;
  58.       while (mantissa != 0.0 && k++ < maxiter) {
  59.         mantissa *= width; // shift double mantissa
  60.         mantissa = modf(mantissa, &intpart);
  61.         num <<= shift;
  62.         num += (long)intpart;
  63.         exponent -= shift;
  64.       }
  65.       if (exponent > 0)
  66.         num <<= (unsigned)exponent;
  67.       else if (exponent < 0)
  68.         den <<= (unsigned)(-exponent);
  69.       if (neg)
  70.         num.negate();
  71.     } // if (x != 0) then
  72.     (*this).normalize();
  73.   };
  74.  
  75.  
  76. LedaRational::LedaRational(int n, int d)
  77.   { if (d == 0) {
  78.       error_handler(1,"Zero denominator!");
  79.     }
  80.     else {
  81.       num = Int(n);
  82.       den = Int(d);
  83.       if (d < 0) {
  84.         num.negate();
  85.         den.negate();
  86.       }
  87.       (*this).normalize();
  88.     }
  89.   };
  90.  
  91.  
  92. LedaRational::LedaRational(const Int& n, const Int& d)
  93.   { if (Ieq0(d)) {
  94.       // d == 0
  95.       error_handler(1,"Zero denominator!");
  96.     }
  97.     else {
  98.       num = n;
  99.       den = d;
  100.       if (Ilt0(d)) {
  101.         // d < 0
  102.         num.negate();
  103.         den.negate();
  104.       }
  105.       (*this).normalize();
  106.     }
  107.   };
  108.  
  109.  
  110.  
  111. // Arithmetic Operators
  112.  
  113. LedaRational& LedaRational::operator+= (const LedaRational& r)
  114.   { num = num * r.den + r.num * den;
  115.     den *= r.den;
  116.     return (*this).normalize();
  117.   };
  118.  
  119. LedaRational& LedaRational::operator-= (const LedaRational& r)
  120.   { num = num * r.den - r.num * den;
  121.     den *= r.den;
  122.     return (*this).normalize();
  123.   };
  124.  
  125. LedaRational& LedaRational::operator*= (const LedaRational& r)
  126.   { num *= r.num;
  127.     den *= r.den;
  128.     return (*this).normalize();
  129.   };
  130.  
  131. LedaRational& LedaRational::operator/= (const LedaRational& r)
  132.   { if (Ieq0(r.num)) {
  133.       // r == 0
  134.       error_handler(1,"Division by 0!");
  135.     }
  136.     else {
  137.       // r.num != 0
  138.       num *= r.den;
  139.       den *= r.num;
  140.       if (Ilt0(den)) {
  141.         num.negate();
  142.         den.negate();
  143.       }
  144.     }
  145.     return (*this).normalize();
  146.   };
  147.  
  148.  
  149.  
  150. // Assignment Operator
  151.  
  152. LedaRational& LedaRational::operator= (const LedaRational& r)
  153.   { if (this == &r) return *this; // to handle r = r correctly
  154.     num = r.num;
  155.     den = r.den;
  156.     return *this;
  157.   };
  158.  
  159.  
  160.  
  161.  
  162. // some useful member-functions
  163.  
  164. void LedaRational::invert()
  165.   { if (Ieq0(num)) {
  166.       error_handler(1,"Zero denominator!");
  167.     }
  168.     else {
  169.       Int tmp = num;
  170.       num = den;
  171.       den = tmp;
  172.       if (Ilt0(den)) {
  173.         num.negate();
  174.         den.negate();
  175.       }
  176.     }
  177.   };
  178.  
  179. LedaRational LedaRational::inverse()
  180.   { if (Ieq0(num)) {
  181.       error_handler(1,"Zero denominator!");
  182.       return (*this);
  183.     }
  184.     else {
  185.       LedaRational tmp(den,num);
  186.       if (Ilt0(num)) {
  187.         (tmp.num).negate();
  188.         (tmp.den).negate();
  189.       }
  190.       return tmp;
  191.     }
  192.   };
  193.  
  194.  
  195.  
  196. // friend functions
  197.  
  198. int compare(const LedaRational& x, int y)
  199.   { int
  200.       xsign = sign(x.num),
  201.       ysign;
  202.     if (y == 0) ysign = 0;
  203.     else ysign = (y > 0) ? 1 : -1;
  204.     if (xsign == 0) { return -ysign; }
  205.     if (ysign == 0) { return xsign; }
  206.     // now (x != 0) && (y != 0)
  207.     int
  208.       diff = xsign - ysign;
  209.     if (diff == 0) {
  210.       Int
  211.         leftop = x.num,
  212.         rightop = Int(y) * x.den;
  213.       if (leftop < rightop) { return -1; }
  214.       else { return (leftop > rightop); }
  215.     }
  216.     else return diff;
  217.   };
  218.  
  219.  
  220. int compare(int x, const LedaRational& y)
  221.   { int
  222.       ysign = sign(y.num),
  223.       xsign;
  224.     if (x == 0) xsign = 0;
  225.     else xsign = (x > 0) ? 1 : -1;
  226.     if (xsign == 0) { return -ysign; }
  227.     if (ysign == 0) { return xsign; }
  228.     // now (x != 0) && (y != 0)
  229.     int
  230.       diff = xsign - ysign;
  231.     if (diff == 0) {
  232.       Int
  233.         leftop = Int(x) * y.den,
  234.         rightop = y.num;
  235.       if (leftop < rightop) { return -1; }
  236.       else { return (leftop > rightop); }
  237.     }
  238.     else return diff;
  239.   };
  240.  
  241.  
  242. // other useful friend functions
  243.  
  244. LedaRational pow(const LedaRational& r, int l)
  245. // no need to normalize since num and den are relatively prime
  246.   { LedaRational mul(r), result(1,1);
  247.     if (l < 0) {
  248.       mul = mul.inverse();
  249.       l = -l;
  250.     }
  251.     for (int i = 1; i <= l; i++) {
  252.       result.num *= mul.num;
  253.       result.den *= mul.den;
  254.     }
  255.     return result;
  256.   };
  257.  
  258. LedaRational pow(const LedaRational& r, Int I)
  259. // no need to normalize since num and den are relatively prime
  260.   { LedaRational mul(r), result(1,1);
  261.     if (Ilt0(I)) {
  262.       mul = mul.inverse();
  263.       I.negate();
  264.     }
  265.     for (Int i = 1; i < I; i++) {
  266.       result.num *= mul.num;
  267.       result.den *= mul.den;
  268.     }
  269.     return result;
  270.   };
  271.  
  272. LedaRational::operator double() const
  273.   { Int
  274.       numvar = num,
  275.       denvar = den;
  276.  
  277.     if (numvar == Int(0)) { return 0; }
  278.     
  279.     const Int MDP = 1000000;    // my_double_precision
  280.     long s = 0;
  281.     Int quot = (numvar / denvar); // integer quotient
  282.  
  283.     while (abs(quot) < MDP) {
  284.       numvar *= 10;
  285.       s++;
  286.       quot = (numvar / denvar);
  287.     }
  288.     // |quot| > MDP
  289.     // num_new == 10^s * num_old
  290.  
  291.     while (abs(quot) > MDP) {
  292.       quot /= 10;
  293.       s--;
  294.     }
  295.     // MDP/10 < |quot| < MDP
  296.     // num_old/den_old == quot * 10^{-s}
  297.  
  298.     double result = (double)longasI(quot);
  299.     // transform Int into double via long
  300.  
  301.     if (s >= 0) {
  302.       for (int i = 0; i < s; i++) { result /= 10; };
  303.     }
  304.     else {
  305.       for (int i = 0; i > s; i--) { result *= 10; };
  306.     }
  307.     return result;
  308.   }; 
  309.  
  310. Int floor(const LedaRational& r)
  311.   { Int x, y;
  312.     Idiv (x, y, r.num, r.den);
  313.     if ((Ilt0(r.num)) && (!Ieq0(y))) x--;
  314.     return x;
  315.   };
  316.  
  317. Int ceil(const LedaRational& r)
  318.   { Int x, y;
  319.     Idiv (x, y, r.num, r.den);
  320.     if ((Ige0(r.num)) && (!Ieq0(y))) x++;
  321.     return x;
  322.   };
  323.  
  324. Int round(const LedaRational& r)
  325.   { Int rem, quot;
  326.     Idiv(quot, rem, r.num, r.den);
  327.     rem <<= 1;
  328.     if (rem >= r.den) {
  329.       if (sign(r.num) >= 0) { quot++; }
  330.       else { quot--; }
  331.     }
  332.     return quot;
  333.   }
  334.  
  335. istream& operator>> (istream& in, LedaRational& r)
  336.   { // Format: "r.num / r.den"
  337.     Int rx, ry;
  338.     char c;
  339.     do in.get(c); while (isspace(c));
  340.     in.putback(c);
  341.  
  342.     in >> rx;
  343.    
  344.     do in.get(c); while (isspace(c));
  345.     if (c != '/') { error_handler(1,"/ expected"); }
  346.  
  347.     do in.get(c); while (isspace(c));
  348.     in.putback(c);
  349.    
  350.     in >> ry;
  351.     r = LedaRational(rx,ry);
  352.     // to guarantee the value is normalized, denominator is nonzero ...
  353.     return in;
  354.   };
  355.